package com.hxzy.controller.admin.upload;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.hxzy.common.constants.MarketConstants;
import com.hxzy.common.enums.AckCode;
import com.hxzy.common.resp.R;
import com.hxzy.common.util.MarketThreadLocalUtil;
import com.hxzy.controller.admin.login.resp.AdminLoginResp;
import com.hxzy.controller.admin.upload.req.ImagePrivateReq;
import com.hxzy.controller.anonymous.upload.AnonyTencentUploadController;
import com.hxzy.service.MerchandiserService;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.http.HttpMethodName;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.*;
import com.qcloud.cos.region.Region;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;

@Log4j2
@RestController
@RequestMapping(value = "/api/tencent")
@Api(tags = "后台-腾讯云对象存储API")
public class AdminTencentUploadController {
 
    private final String  BUCKET_NAME = "market-1300180953";

    @Autowired
    private MerchandiserService merchandiserService;

    /**
     * 创建 COSClient 实例，这个实例用来后续调用请求
     * @return
     */
    private COSClient createCOSClient() {
        //从这里复制过来的  https://cloud.tencent.com/document/product/436/10199
        // 设置用户身份信息。
        // SECRETID 和 SECRETKEY 请登录访问管理控制台 https://console.cloud.tencent.com/cam/capi 进行查看和管理
        String secretId = "AKIDgOuFLDtLYV0JOEoBLHzUqxohQyTkncDa";
        String secretKey = "A6pMgngRmskNo10nNnDUYaVEj082rVvB";
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);

        // ClientConfig 中包含了后续请求 COS 的客户端设置：
        ClientConfig clientConfig = new ClientConfig();

        // 设置 bucket 的地域
        // COS_REGION 请参见 https://cloud.tencent.com/document/product/436/6224
        clientConfig.setRegion( new Region("ap-chongqing"));

        // 设置请求协议, http 或者 https
        // 5.6.53 及更低的版本，建议设置使用 https 协议
        // 5.6.54 及更高版本，默认使用了 https
        clientConfig.setHttpProtocol(HttpProtocol.https);
        // 以下的设置，是可选的：
        // 设置 socket 读取超时，默认 30s
        clientConfig.setSocketTimeout(30*1000);
        // 设置建立连接超时，默认 30s
        clientConfig.setConnectionTimeout(30*1000);

        // 生成 cos 客户端。
        return new COSClient(cred, clientConfig);
    }




    @ApiOperation(value = "图片上传，只支持(png,jpg)")
    @PostMapping(value = "/image/upload")
    @ApiImplicitParam(name = "file", value = "上传的文件", dataType = "_File", dataTypeClass = MultipartFile.class, required = true)
    public R imageUpload(@RequestPart MultipartFile file) throws IOException {
        if (file.isEmpty()) {
            return R.build(AckCode.FILE_NOT_EMPTY);
        }

        //文件后缀名
        String ext="";
        //上传文件的名称
        String originalFileName=file.getOriginalFilename();

        //这里是以blob二进制数据上传，需要特殊处理
        if("blob".equals(originalFileName)){
            //当前上传文件的类型
            String mimeType=file.getContentType();
            //image/png  ,image/jpeg  ,image/jpeg
            Map<String,String> mimeTypeMap=new HashMap<>(16);
            mimeTypeMap.put("image/png",".png");
            mimeTypeMap.put("image/jpeg",".jpg");
            if(!mimeTypeMap.containsKey(mimeType)){
                return R.build(AckCode.UPLOAD_TYPE_ERROR_IMAGE);
            }
            ext=mimeTypeMap.get(mimeType);
        }else{
            //得到文件扩展名
            int lastIndex=originalFileName.lastIndexOf('.');
            if(lastIndex<=0){
                return R.build(AckCode.UPLOAD_TYPE_ERROR);
            }
            ext=originalFileName.substring(lastIndex).toLowerCase();
            boolean contains = Arrays.asList(".png", ".jpg", ".jpeg").contains(ext.toLowerCase(Locale.ROOT));
            if(!contains){
                return R.build(AckCode.UPLOAD_TYPE_ERROR_IMAGE);
            }
        }

        //生成一个文件名
        String newFileName= UUID.randomUUID().toString()+ext;

        //取得当前用户
        AdminLoginResp  adminLoginResp= MarketThreadLocalUtil.ADMIN_THREAD_LOCAL.get();

        //开始上传
        COSClient cosClient = this.createCOSClient();
        // 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式



        // 对象键(Key)是对象在存储桶中的唯一标识 (文件名)
        String key = StrUtil.format("/{}/{}/{}",adminLoginResp.getPermissions(),adminLoginResp.getId(),newFileName);

        // 这里创建一个 ByteArrayInputStream 来作为示例，实际中这里应该是您要上传的 InputStream 类型的流
        ObjectMetadata objectMetadata = new ObjectMetadata();
        // 上传的流如果能够获取准确的流长度，则推荐一定填写 content-length
        // 如果确实没办法获取到，则下面这行可以省略，但同时高级接口也没办法使用分块上传了
        objectMetadata.setContentLength(file.getSize());

        InputStream fis=file.getInputStream();

        //文件上传配置
        PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET_NAME, key, fis, objectMetadata);

        // 设置存储类型（如有需要，不需要请忽略此行代码）, 默认是标准(Standard), 低频(standard_ia)
        // 更多存储类型请参见 https://cloud.tencent.com/document/product/436/33417
        putObjectRequest.setStorageClass(StorageClass.Standard_IA);

        try {
            PutObjectResult putObjectResult  = cosClient.putObject(putObjectRequest);

            //自定义返回结果
            Map<String,String> dataMap=new HashMap<>();
            dataMap.put("image_url", MarketConstants.TENCENT_IMAGE_SERVICE+key);
            dataMap.put("file_name", key);
            dataMap.put("original_file_name",originalFileName);

            return R.okHasData(dataMap);

        } catch (CosClientException e) {
            log.error(e);
            return R.build(AckCode.UPLOAD_FILE_ERROR);
        } finally {
            //上传文件流要关闭
            fis.close();
            // 确认本进程不再使用 cosClient 实例之后，关闭之
            cosClient.shutdown();
        }
    }

    @ApiOperation(value = "删除图片")
    @DeleteMapping(value = "/remove/image/{fileName}")
    public R imageRemove(@PathVariable(value = "fileName") String fileName) {
        if(StrUtil.isBlank(fileName)){
            return R.build(AckCode.SYSTEM_PARAM_FAIL);
        }

        //取得当前用户
        AdminLoginResp  adminLoginResp= MarketThreadLocalUtil.ADMIN_THREAD_LOCAL.get();

        //开始上传
        COSClient cosClient = this.createCOSClient();
        // 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式

        // 对象键(Key)是对象在存储桶中的唯一标识 (文件名)
        String key = StrUtil.format("/{}/{}/{}",adminLoginResp.getPermissions(),adminLoginResp.getId(),fileName);


        try {

            boolean objectExists = cosClient.doesObjectExist(BUCKET_NAME, key);
            if(objectExists){
                cosClient.deleteObject(BUCKET_NAME, key);
            }else{
                return R.build(AckCode.FILE_NOT_EXIST);
            }

        } catch (CosClientException e) {
            log.error(e);
            return  R.build(AckCode.REMOVE_FILE_ERROR);
        }finally {
            // 确认本进程不再使用 cosClient 实例之后，关闭即可
            cosClient.shutdown();
        }

        return R.ok();
    }



    @ApiOperation(value = "访问商家私密私有桶的信息")
    @GetMapping(value = "/merchandiser/image")
    public void getMerchandiserPrivateUrl(@Valid ImagePrivateReq req, HttpServletResponse response) throws URISyntaxException, IOException {


        COSClient cosClient = createCOSClient();

        String bucketName = "private-user-1300180953";
        // 对象键(Key)是对象在存储桶中的唯一标识。详情请参见 [对象键](https://cloud.tencent.com/document/product/436/13324)
        String key=this.merchandiserService.searchImageKey(req);

        //生成预签名的地址  https://cloud.tencent.com/document/product/436/35217
        GeneratePresignedUrlRequest request =
                new GeneratePresignedUrlRequest(bucketName, key, HttpMethodName.GET);
        //设置临时URL有效期为1分钟
        Date expiration = DateUtil.offsetMinute(new Date(), 1);
        request.setExpiration(expiration);
        URL url = cosClient.generatePresignedUrl(request);
        log.info(url);
        cosClient.shutdown();

        //手动访问
        RestTemplate restTemplate=new RestTemplate();
        ResponseEntity<Resource> forEntity = restTemplate.getForEntity(url.toURI(), Resource.class);
        InputStream body = forEntity.getBody().getInputStream();

        //加载本地水印
        String waterFilePath= AnonyTencentUploadController.class.getResource("/").toString().replaceAll("file:/","");
        File waterImageFile = new File(waterFilePath+"water.png");

        //生成响应流输出给客户端
        Thumbnails.of(body)
                .scale(1.0)
                .watermark(Positions.CENTER, ImageIO.read(waterImageFile), 0.5f)
                .toOutputStream(response.getOutputStream());


    }

}
